meson: Reduce useless relinking on reconfigure
authorNirbheek Chauhan <nirbheek@centricular.com>
Fri, 3 Apr 2020 11:58:18 +0000 (17:28 +0530)
committerNirbheek Chauhan <nirbheek@centricular.com>
Fri, 3 Apr 2020 13:11:55 +0000 (18:41 +0530)
When we reconfigure, `configure_file()` is called again, and
`*.gresource.xml` files are regenerated, which causes many (all?)
binaries to be relinked. Now we only write those out if the contents
actually changed (or if the output didn't already exist).

This is exactly what Meson already does with `configure_file()` when
`command:` is not used.

While we're at it, also do the same for `gen-c-array.py` and
`gentypefuncs.py` for completeness. Now even if the input to those
changes, re-building of those custom targets may not result in
relinking if the outputted C files have the same contents.

gdk/broadway/gen-c-array.py
gdk/gen-gdk-gresources-xml.py
gsk/gen-gsk-gresources-xml.py
gtk/gen-gtk-gresources-xml.py
gtk/gentypefuncs.py

index afffda34e5ee3623bc664f5480d95e4286e51182..a25d2e4159e33a9ae2d79c8ae17302d0533c6b19 100644 (file)
@@ -1,21 +1,43 @@
 #!/usr/bin/env python3
 
+import os
 import argparse
 import sys
+import filecmp
+
+def replace_if_changed(new, old):
+  '''
+  Compare contents and only replace if changed to avoid triggering a rebuild.
+  '''
+  try:
+    changed = not filecmp.cmp(new, old, shallow=False)
+  except FileNotFoundError:
+    changed = True
+  if changed:
+    os.replace(new, old)
+  else:
+    os.remove(new)
 
 parser = argparse.ArgumentParser()
 parser.add_argument('--array-name', help='The name of the array variable')
-parser.add_argument('--output', metavar='FILE', help='Output file',
-                    type=argparse.FileType('w'),
-                    default=sys.stdout)
+parser.add_argument('--output', metavar='STRING', help='Output filename',
+                    default=None)
 parser.add_argument('input', metavar='FILE', help='The input file',
                     type=argparse.FileType('r'))
 
 args = parser.parse_args()
 
-args.output.write('static const char {}[] = {{\n'.format(args.array_name))
-for line in args.input:
-    for ch in line:
-        args.output.write('  0x{:02x},\n'.format(ord(ch)))
+if args.output is None:
+    output = sys.stdout
+else:
+    output = args.output + '~'
+
+with open(output, 'w') as f:
+    f.write('static const char {}[] = {{\n'.format(args.array_name))
+    for line in args.input:
+        for ch in line:
+            f.write('  0x{:02x},\n'.format(ord(ch)))
+    f.write('};')
 
-args.output.write('};')
+if args.output is not None:
+    replace_if_changed(output, args.output)
index 694a9159aa5c25534ade69d1e1da219fa7f7a266..11c63552a9b73dff2078033d0cd49f7636db08e8 100644 (file)
@@ -5,6 +5,20 @@
 # Usage: gen-gdk-gresources-xml SRCDIR_GDK [OUTPUT-FILE]
 
 import os, sys
+import filecmp
+
+def replace_if_changed(new, old):
+  '''
+  Compare contents and only replace if changed to avoid triggering a rebuild.
+  '''
+  try:
+    changed = not filecmp.cmp(new, old, shallow=False)
+  except FileNotFoundError:
+    changed = True
+  if changed:
+    os.replace(new, old)
+  else:
+    os.remove(new)
 
 srcdir = sys.argv[1]
 
@@ -26,8 +40,9 @@ xml += '''
 
 if len(sys.argv) > 2:
   outfile = sys.argv[2]
-  f = open(outfile, 'w')
-  f.write(xml)
-  f.close()
+  tmpfile = outfile + '~'
+  with open(tmpfile, 'w') as f:
+    f.write(xml)
+  replace_if_changed(tmpfile, outfile)
 else:
   print(xml)
index 1032d84ad94c7f15c9ce2f3c9dfc542c5e20fe0a..5db5044b09f613f13026b21a898b0c91a6a0d0cc 100644 (file)
@@ -5,6 +5,20 @@
 # Usage: gen-gsk-gresources-xml OUTPUT-FILE [INPUT-FILE1] [INPUT-FILE2] ...
 
 import os, sys
+import filecmp
+
+def replace_if_changed(new, old):
+  '''
+  Compare contents and only replace if changed to avoid triggering a rebuild.
+  '''
+  try:
+    changed = not filecmp.cmp(new, old, shallow=False)
+  except FileNotFoundError:
+    changed = True
+  if changed:
+    os.replace(new, old)
+  else:
+    os.remove(new)
 
 source_shaders = []
 vulkan_compiled_shaders = []
@@ -45,8 +59,9 @@ xml += '''
 
 if len(sys.argv) > 1 and sys.argv[1] != '-':
   outfile = sys.argv[1]
-  f = open(outfile, 'w')
-  f.write(xml)
-  f.close()
+  tmpfile = outfile + '~'
+  with open(tmpfile, 'w') as f:
+    f.write(xml)
+  replace_if_changed(tmpfile, outfile)
 else:
   print(xml)
index eb56d8e478544ffada9cb82f3541bba1b97c463d..a816970a88c8a609de839a0c54745e01b62bcc6c 100644 (file)
@@ -5,6 +5,20 @@
 # Usage: gen-gtk-gresources-xml SRCDIR_GTK [OUTPUT-FILE]
 
 import os, sys
+import filecmp
+
+def replace_if_changed(new, old):
+  '''
+  Compare contents and only replace if changed to avoid triggering a rebuild.
+  '''
+  try:
+    changed = not filecmp.cmp(new, old, shallow=False)
+  except FileNotFoundError:
+    changed = True
+  if changed:
+    os.replace(new, old)
+  else:
+    os.remove(new)
 
 srcdir = sys.argv[1]
 
@@ -78,8 +92,9 @@ xml += '''
 
 if len(sys.argv) > 2:
   outfile = sys.argv[2]
-  f = open(outfile, 'w')
-  f.write(xml)
-  f.close()
+  tmpfile = outfile + '~'
+  with open(tmpfile, 'w') as f:
+    f.write(xml)
+  replace_if_changed(tmpfile, outfile)
 else:
   print(xml)
index b17b7233a1e38877cf9db6cd0b1a5b193d68d14a..c67c5c4a5fd3b2cf4058512d392b45a515c934c4 100644 (file)
@@ -4,6 +4,20 @@
 import sys
 import re
 import os
+import filecmp
+
+def replace_if_changed(new, old):
+  '''
+  Compare contents and only replace if changed to avoid triggering a rebuild.
+  '''
+  try:
+    changed = not filecmp.cmp(new, old, shallow=False)
+  except FileNotFoundError:
+    changed = True
+  if changed:
+    os.replace(new, old)
+  else:
+    os.remove(new)
 
 debug = os.getenv('GTK_GENTYPEFUNCS_DEBUG') is not None
 
@@ -50,6 +64,7 @@ for f in funcs:
 
 if debug: print (len(funcs), 'functions')
 
-ofile = open(out_file, "w")
-ofile.write(file_output)
-ofile.close()
+tmp_file = out_file + '~'
+with open(tmp_file, 'w') as f:
+    f.write(file_output)
+replace_if_changed(tmp_file, out_file)